#include "TextureManager.h"

int TextureManager::TEXTURE_SIZE = 768;
int TextureManager::SHADOW_MAP_SIZE = 768;
D3DFORMAT TextureManager::RT_FORMAT = D3DFMT_A8R8G8B8;
D3DFORMAT TextureManager::DEPTH_RT_FORMAT = D3DFMT_R32F;
bool TextureManager::SUPPORT_MRT = true;
TextureManager::TextureManager(LPDIRECT3DDEVICE9 device) : DeviceHolder(device)
{
}

TextureManager::~TextureManager(void)
{
	for(vector<MTexture>::const_iterator itr = textures.begin(); itr != textures.end(); itr++) 
	{
		MTexture mTex = (MTexture)*itr;
		if (mTex.isRTarget)
		{
			continue;
		}
		if (mTex.released == false)
		{
			ULONG references = mTex.texture->Release();
			if (references != 0)
			{
				ERROR_KILL(0, L"Texture released twice!");
			}
			mTex.released = true;
		}
	}

	for(vector<MSurface>::const_iterator itr = surfaces.begin(); itr != surfaces.end(); itr++) 
	{
		MSurface mSurf = (MSurface)*itr;
		if (mSurf.released == false)
		{
			ULONG references = mSurf.surface->Release();
			getMTexture(mSurf.alias)->texture->Release();
			if (references != 0)
			{
				ERROR_KILL(0, L"Texture released twice!");
			}
			mSurf.released = true;
		}
	}
	textures.clear();
	surfaces.clear();
}

LPDIRECT3DTEXTURE9 TextureManager::makeTexture (
	const LPCWSTR alias, 
	const D3DFORMAT format,
	const UINT width,
	const UINT height)
{

	LPDIRECT3DTEXTURE9 tex;
	HRESULT hr = device->CreateTexture(
		width,
		height,
		1,
		D3DUSAGE_RENDERTARGET,
		format,
		D3DPOOL_DEFAULT,
		&tex,
		NULL);
	if(FAILED(hr) && format != D3DFMT_A8R8G8B8)
	{
		MessageBox(NULL, DXGetErrorDescription(hr),L"Trying again to make a texture.",MB_OK);
		hr = device->CreateTexture(
			width,
			height,
			1,
			D3DUSAGE_RENDERTARGET,
			D3DFMT_A8R8G8B8,
			D3DPOOL_DEFAULT,
			&tex,
			NULL);
		if(FAILED(hr))
		{
			MessageBox(NULL, DXGetErrorDescription(hr),L"Texture creation error.",MB_OK);
		}
	}
	
	if (hr == D3DERR_INVALIDCALL)
	{
		ERROR_KILL(hr, L"makeTexture D3DERR_INVALIDCALL");
	}

	if (hr == D3DERR_OUTOFVIDEOMEMORY)
	{
		ERROR_KILL(hr, L"makeTexture D3DERR_OUTOFVIDEOMEMORY");
	}

	if (hr == E_OUTOFMEMORY)
	{
		ERROR_KILL(hr, L"makeTexture E_OUTOFMEMORY");
	}

	ERROR_KILL(hr, L"Failed to make a texture");

	addTexture(tex, alias, true);

	return tex;
}

void TextureManager::makeRenderTarget (
		const LPCWSTR alias,
		const D3DFORMAT format,
		const UINT width,
		const UINT height)
	{
		LPDIRECT3DSURFACE9 surface = NULL;
		makeTexture(alias, format, width, height);
		HRESULT hr = getMTexture(alias)->texture->GetSurfaceLevel(0, &surface);
		if( FAILED(hr) ) MessageBox(NULL,DXGetErrorDescriptionW(hr),L"Error setting surface level.",MB_OK);
		addSurface(surface, alias);
	}

LPDIRECT3DTEXTURE9 TextureManager::loadTexture (const LPCWSTR fileName, const LPCWSTR alias)
{
	LPDIRECT3DTEXTURE9 tex;
	HRESULT hr = D3DXCreateTextureFromFile(device, fileName, &tex);

	if( FAILED(hr) ) MessageBox(NULL,DXGetErrorDescriptionW(hr),L"Failed to load texture.",MB_OK);
	ERROR_KILL(hr, L"Failed to load a texture");

	if (alias != NULL)
	{
		addTexture(tex, alias);
	}
	else
	{
		addTexture(tex, fileName);
	}

	return tex;
}

void TextureManager::addTexture(const LPDIRECT3DTEXTURE9 texture, const LPCWSTR alias, const bool isRT)
{
	MTexture tex;
	tex.alias = alias;
	tex.texture = texture;
	tex.released = false;
	tex.isRTarget = isRT;
	textures.push_back(tex);
}

void TextureManager::addSurface(const LPDIRECT3DSURFACE9 surface, const LPCWSTR alias)
{
	MSurface surf;
	surf.alias = alias;
	surf.surface = surface;
	surf.released = false;
	surfaces.push_back(surf);
}

LPDIRECT3DTEXTURE9 TextureManager::getTexture(const LPCWSTR alias)
{
	return getMTexture(alias)->texture;
}

LPDIRECT3DSURFACE9 *TextureManager::getSurface(const LPCWSTR alias)
{
	return &getMSurface(alias)->surface;
}



MTexture *TextureManager::getMTexture(const LPCWSTR alias)
{
	std::vector<MTexture>::const_iterator itr;
	int index = 0;
	for(itr = textures.begin(); 
		itr != textures.end();
		itr++) 
	{
			MTexture mTex = (MTexture)*itr;
			if (wcscmp(mTex.alias, alias) == 0) {
				return &textures[index];
			}
			index++;
	}

	ERROR_KILL(0, L"Failed to get the texture.");
	return NULL;
}

MSurface *TextureManager::getMSurface(const LPCWSTR alias)
{
	std::vector<MSurface>::const_iterator itr;
	int index = 0;
	for(itr = surfaces.begin(); 
		itr != surfaces.end();
		itr++) 
	{
			MSurface mSurf = (MSurface)*itr;
			if (wcscmp(mSurf.alias, alias) == 0) {
				return &surfaces[index];
			}
			index++;
	}

	ERROR_KILL(0, L"Failed to get the surface");
	return NULL;
}
